package com.gxa.hotel.sso.service.impl;

import com.fasterxml.jackson.databind.ObjectMapper;

import com.gxa.hotel.core.exception.BusinessException;
import com.gxa.hotel.core.exception.ExceptionCode;
import com.gxa.hotel.sso.entity.User;
import com.gxa.hotel.sso.repository.UserRepository;
import com.gxa.hotel.sso.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundValueOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @Transactional 处理持久层的事务,还能在redis操作完毕时关闭连接
 */
@Service
@Transactional(rollbackFor = Throwable.class)
public class UserServiceImpl implements UserService {
    @Autowired
    private RedisTemplate<String,Object> redisTemplate=null;

    @Autowired
    UserRepository userRepository;

    @Autowired
    HttpServletRequest request;

    private static final String SALT="LuanShuaiDeYiPi";
    @Override
    public String login(String phone, String code) throws Exception{
        //一键登录
        //1.获取redis服务器存储的验证码
        Object redisCode = redisTemplate.opsForValue().get(SmsServiceImpl.LOGIN_SMS + phone);

        //验证码失效的判断,如果为空则抛出异常
        if (StringUtils.isEmpty(redisCode)){
            throw new BusinessException(ExceptionCode.EXPIRE_CODE);
        }
        //对验证码做校验, 如果不一致则抛出异常
        if (!code.equals(redisCode)){
            throw new BusinessException(ExceptionCode.WRONG_CODE);
        }
        //标志着用户输入的手段和redis服务器中存储的一致(短信合法性)
        //校验完成, 删除验证码

        redisTemplate.delete(SmsServiceImpl.LOGIN_SMS);
        //校验完成, 从mysql数据库中查找用户信息
        User findedUser = userRepository.findByPhoneEquals(phone);
        //如果用户不存在, 则匿名注册,匿名格式: "用户:"+phone , 并指定用户状态
        if (findedUser==null){
            //创建一个临时用户name

            //创建一个User的实例
            findedUser=new User();
            //给当前实例添加状态信息
            findedUser.setName("user"+phone);
            //冻结
            findedUser.setStatus(1);
           //手机号
            findedUser.setPhone(phone);

        }

        //如果用户存在, 但状态不为1,表示冻结状态, 抛出异常
        if (findedUser.getStatus()!=1){
            throw new BusinessException(ExceptionCode.WRONG_USER_STATUS);
        }
        //无论用户注册/登录,都需要获取的状态信息
        //ip
        findedUser.setIpAddress(request.getRemoteAddr());
        //最后一次登录时间
        findedUser.setLastLoginTime(LocalDateTime.now());
        //登录类型 1.PC
        findedUser.setLoginType(1);
        //如果用户存在,获取上次的token,如果不为空移除redis中上一次的登录信息

        //生成token，存储登录信息(json),利用处理后的UUID
        String token= UUID.randomUUID().toString().replace("-","");
        if (!StringUtils.isEmpty(findedUser.getToken())){
            Boolean delete = redisTemplate.delete(SALT+findedUser.getToken());
            System.out.println(delete);
        }
        //处理登录
        // 设置ip,设置token,更新
        findedUser.setToken(token);



        //PC:2小时 手机端H5:2小时 APP:1个月
        Integer expire=null;
        if (findedUser.getLoginType()==1){
            expire=2;
        }else if(findedUser.getLoginType()==2){
            expire=2;
        }else{
            expire=24*31;
        }

        //不管是注册还是登录,save方法都要执行
        //注册:添加
        //登录:修改
        User save = userRepository.save(findedUser);
        // redis添加token信息和过期时间
        String key=SALT+token;
        ObjectMapper objectMapper=new ObjectMapper();
        String value = objectMapper.writeValueAsString(save);

        redisTemplate.opsForValue().set(key,value,expire,TimeUnit.HOURS);
        return token;
    }

    @Override
    public User checkWithToken(String token) throws Exception {

        //从redis中获取用户信息
        String key=SALT+token;

        BoundValueOperations<String, Object> stringOps = redisTemplate.boundValueOps(key);
        //判断一下redis是否存在该key
        //存在既获取
        //不存在抛出异常
        Object redisToken = stringOps.get();
        if (StringUtils.isEmpty(redisToken)){
            throw new BusinessException(ExceptionCode.WRONG_TOKEN);
        }
        //为了业务的持续期更长(订单/支付)

        //使用jackson将token保存的用户json数据转换为User对象并返回
        ObjectMapper objectMapper = new ObjectMapper();
        User user = objectMapper.readValue(redisToken.toString(), User.class);
        stringOps.expire(2,TimeUnit.HOURS);
        return user;
    }
}
